﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Input;
using System.Windows.Controls.Ribbon;
using SHomeWorkshop.LunarConcept.Controls;
using System.Xml;
using SHomeWorkshop.LunarConcept.Tools;
using SHomeWorkshop.LunarConcept.ModifingManager;
using System.Windows;
using SHomeWorkshop.LunarConcept.Widgets;
using System.Windows.Controls;
using SHomeWorkshop.LunarConcept.Widgets.Interfaces;

namespace SHomeWorkshop.LunarConcept.Commands
{
    /// <summary>
    /// 创建时间：2012年1月16日
    /// 创建者：  杨震宇
    /// 
    /// 主要用途：在当前主编辑器中移动部件。
    /// </summary>
    public static class MoveWidgetsCommand
    {
        #region 构造方法=====================================================================================================

        /// <summary>
        /// [静态][构造方法]
        /// 
        /// ——此方法会初始化并向WPF系统注册一个RoutedUICommand。
        /// </summary>
        static MoveWidgetsCommand()//类型构造器
        {
            routedUICmd = new RoutedUICommand(
                "MoveWidgetsCommand",
                "MoveWidgetsCommand",
                typeof(MoveWidgetsCommand),//创建RoutedUICommand对象
                null);//本程序考虑支持“命令模式”因此，这些命令完全没有必要直接支持快捷键。

            cmdBinding.Command = routedUICmd;
            cmdBinding.CanExecute += new CanExecuteRoutedEventHandler(cmdBinding_CanExecute);
            cmdBinding.Executed += new ExecutedRoutedEventHandler(cmdBinding_Executed);
        }

        #endregion

        #region 字段与属性===================================================================================================

        private static CommandBinding cmdBinding = new CommandBinding();
        /// <summary>
        /// 用在主窗口CommandBindings集合中的命令绑定。
        /// 
        /// 它的Command是RoutedUICommand。
        /// ——因此，RoutedUICommand是否可以运行将由CmdBinding的CanExecute事件决定。
        /// ——而且，RoutedUICommand的执行也是通过CmdBinding的Execute事件来进行的。
        /// </summary>
        public static CommandBinding CmdBinding
        {
            get { return cmdBinding; }
        }

        private static RoutedUICommand routedUICmd;
        /// <summary>
        /// [只读静态属性]表示在WPF系统中注册的一个RoutedUICommand。
        /// ——必须和CommandBinding配合才能使用。
        ///     CommandBinding要添加到主窗口的CommandBindings集合中；
        ///     RoutedUICommand则要向WPF系统注册。
        ///     
        /// ★说明：使用静态属性是因为这样在Xaml代码中比较便于绑定。
        /// </summary>
        public static RoutedUICommand RoutedUICmd
        {
            get { return routedUICmd; }
        }

        #endregion

        #region 方法=========================================================================================================

        /// <summary>
        /// 判断命令是否可以执行。
        /// ——由于可以直接调用Execute()方法，因此，即使被禁用，也不是不能执行相关功能！！！
        /// </summary>
        static void cmdBinding_CanExecute(object sender, CanExecuteRoutedEventArgs e)
        {
            //考虑到性能问题，全部取消此判断。反正执行时会判断。
            //if (Globals.MainWindow == null)
            //{
            //    e.CanExecute = false; return;
            //}

            //EditorManager manager = Globals.MainWindow.EditorManager;
            //if (manager == null)
            //{
            //    e.CanExecute = false; return;
            //}

            //PageEditor pe = manager.GetMainSelectedPageEditor();
            //if (pe == null)
            //{
            //    e.CanExecute = false; return;
            //}

            //List<Widget> selectedWidgets = pe.GetSelectedWidgetsList(true);
            //if (selectedWidgets.Count <= 0)
            //{
            //    e.CanExecute = false;
            //    return;
            //}

            e.CanExecute = true;
            return;
        }

        /// <summary>
        /// 命令被触发时，会调用本事件处理器方法。
        /// ——本方法实际上是调用ExeCute()这个静态方法来实现特定功能。
        /// </summary>
        static void cmdBinding_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            //Execute();
        }

        /// <summary>
        /// [公开静态方法]即使此命令处于禁用状态，也可以通过代码调用此方法来执行特定任务！！！
        /// 
        /// 当被绑定的命令被调用（触发）时，会引发cmdBinding_Executed事件。
        /// 在cmdBinding_Executed事件处理器方法中已添加了调用Execute()方法的代码。
        /// 
        /// ——因此，触发命令，就相当于调用此方法！！！
        /// </summary>
        public static string Execute(MouseLeftButtonDraggingEventArgs e)
        {
            PageEditor pe = e.MasterPageEditor;
            if (pe == null) return "　　未传入所在页面。";

            List<Widgets.Widget> selectedWidgetList = pe.GetSelectedWidgetsList();

            ModifingInfo info = new ModifingInfo() { ModifingDescription = "拖动部件位置" };

            if (pe.MasterManager != null)
            {
                pe.MasterManager.GetSelectedPageEditorStatus(info);
                pe.MasterManager.GetSelectedWidgetStatus_Old(info);
                pe.MasterManager.GetSelectedWidgetStatus_New(info);

                Widgets.Widget w = pe.GetMainSelectedWidget();
                if (w != null)
                {
                    info.NewMainSelectedWidgetID = w.Id;
                }
            }

            ModifingItem<Action, ModifingInfo> mi = new ModifingItem<Action, ModifingInfo>(info);

            List<ILinkableLine> linkedLines = pe.GetLinkedLines(selectedWidgetList);

            int lockedWidgetsCount = 0;

            bool autoAlignment = Globals.MainWindow.RtbtnAutoAlignment.IsChecked == true;

            foreach (Widgets.Widget w in selectedWidgetList)
            {
                if (w.IsLocked)
                {
                    w.RefreshLocation();
                    lockedWidgetsCount++;
                    continue;
                }

                Widgets.ContentWidget cw = w as Widgets.ContentWidget;
                if (cw != null)
                {
                    Point newLocation = new Point(Canvas.GetLeft(cw), Canvas.GetTop(cw));

                    if (newLocation.X < 0) newLocation.X = 0;
                    if (newLocation.Y < 0) newLocation.Y = 0;

                    if ((newLocation.X + cw.ActualWidth) > pe.ActualWidth)
                    {
                        newLocation.X = newLocation.X - (newLocation.X + cw.ActualWidth - pe.ActualWidth);
                    }

                    if ((newLocation.Y + cw.ActualHeight) > pe.ActualHeight)
                    {
                        newLocation.Y = newLocation.Y - (newLocation.Y + cw.ActualHeight - pe.ActualHeight);
                    }

                    Point oldLocation = cw.Location;
                    //if (Math.Abs(newLocation.X - oldLocation.X) <= 4 &&
                    //    Math.Abs(newLocation.Y - oldLocation.Y) <= 4) continue;//位置太近，不视为拖动。
                    //容易让人误会，还是取消这个限制比较好。2014年2月9日
                    if (Math.Abs(newLocation.X - oldLocation.X) <= 0 &&
                        Math.Abs(newLocation.Y - oldLocation.Y) <= 0) continue;

                    double hOffset = double.MaxValue, vOffset = double.MaxValue;
                    if (autoAlignment)
                    {
                        //尝试自动对齐

                        //先尝试中心坐标对齐
                        //需要取出最接近的位置
                        Point center = new Point(newLocation.X + cw.ActualWidth / 2, newLocation.Y + cw.ActualHeight / 2);

                        foreach (UIElement ue in cw.MasterEditor.MainCanvas.Children)
                        {
                            Widget widget = ue as ContentWidget;
                            if (widget == null)
                            {
                                widget = ue as ShapeWidget;
                                if (widget == null) continue;
                            }

                            if( widget == cw )continue;
                            if(selectedWidgetList.Contains(widget)) continue;
                            
                            Point widgetCenter = new Point(widget.OuterRect.Left + widget.OuterRect.Width / 2, widget.OuterRect.Top + widget.OuterRect.Height / 2);
                            double h = double.MaxValue, v = double.MaxValue, tmph = double.MaxValue, tmpv = double.MaxValue;

                            tmph = widgetCenter.X - center.X;
                            tmpv = widgetCenter.Y - center.Y;

                            if (Math.Abs(tmph) < Math.Abs(h)) h = tmph;
                            if (Math.Abs(tmpv) < Math.Abs(v)) v = tmpv;

                            #region 要全考虑似乎不容易实现，易出错。暂时不管了。2014年2月11日

                            //tmph = widget.OuterRect.Left - cw.OuterRect.Left;
                            //tmpv = widget.OuterRect.Top - cw.OuterRect.Top;

                            //if (Math.Abs(tmph) < Math.Abs(h)) h = tmph;
                            //if (Math.Abs(tmpv) < Math.Abs(v)) v = tmpv;

                            //tmph = widget.OuterRect.Left - cw.OuterRect.Right;
                            //tmpv = widget.OuterRect.Top - cw.OuterRect.Bottom;

                            //if (Math.Abs(tmph) < Math.Abs(h)) h = tmph;
                            //if (Math.Abs(tmpv) < Math.Abs(v)) v = tmpv;

                            //tmph = widget.OuterRect.Left - center.X;
                            //tmpv = widget.OuterRect.Top - center.Y;

                            //if (Math.Abs(tmph) < Math.Abs(h)) h = tmph;
                            //if (Math.Abs(tmpv) < Math.Abs(v)) v = tmpv;

                            //tmph = widgetCenter.X - cw.OuterRect.Left;
                            //tmpv = widgetCenter.Y - cw.OuterRect.Top;

                            //if (Math.Abs(tmph) < Math.Abs(h)) h = tmph;
                            //if (Math.Abs(tmpv) < Math.Abs(v)) v = tmpv;

                            //tmph = widgetCenter.X - cw.OuterRect.Right;
                            //tmpv = widgetCenter.Y - cw.OuterRect.Bottom;

                            //if (Math.Abs(tmph) < Math.Abs(h)) h = tmph;
                            //if (Math.Abs(tmpv) < Math.Abs(v)) v = tmpv;

                            //tmph = widget.OuterRect.Right - cw.OuterRect.Left;
                            //tmpv = widget.OuterRect.Bottom - cw.OuterRect.Top;

                            //if (Math.Abs(tmph) < Math.Abs(h)) h = tmph;
                            //if (Math.Abs(tmpv) < Math.Abs(v)) v = tmpv;

                            //tmph = widget.OuterRect.Right - center.Y;
                            //tmpv = widget.OuterRect.Bottom - center.Y;

                            //if (Math.Abs(tmph) < Math.Abs(h)) h = tmph;
                            //if (Math.Abs(tmpv) < Math.Abs(v)) v = tmpv;

                            //tmph = widget.OuterRect.Right - cw.OuterRect.Right;
                            //tmpv = widget.OuterRect.Bottom - cw.OuterRect.Bottom;

                            //if (Math.Abs(tmph) < Math.Abs(h)) h = tmph;
                            //if (Math.Abs(tmpv) < Math.Abs(v)) v = tmpv;
                            
                            #endregion

                            if (Math.Abs(h) < Math.Abs(hOffset)) hOffset = h;
                            if (Math.Abs(v) < Math.Abs(vOffset)) vOffset = v;
                        }
                    }

                    //添加对齐辅助线时添加了自动吸附，但让人迷惑不解。2014年7月26日去除之
                    //if (hOffset < double.MaxValue && Math.Abs(hOffset) < 10) newLocation.X += hOffset;
                    //if (vOffset < double.MaxValue && Math.Abs(vOffset) < 10) newLocation.Y += vOffset;

                    Action actLocation = new Action(pe.Id, cw.Id, cw.GetType().Name, XmlTags.LocationTag,
                        cw.Location.ToString(), newLocation.ToString());

                    cw.Location = newLocation;
                    mi.AddAction(actLocation);
                    continue;
                }

                //如果是线型部件。注意：ShapeWidget是LineWidget的子类。
                Widgets.LineWidget lw = w as Widgets.LineWidget;
                if (lw != null)
                {
                    ILinkableLine linkedLine = lw as ILinkableLine;
                    if (linkedLine != null && linkedLine.IsLinked)
                    {
                        linkedLine.RefreshLocation();
                        continue;//如果是连接线，直接跳过。
                    }

                    lw.DropWidget(mi, e.EndPoint);
                }
            }

            //刷新挂接的连接线的位置
            pe.RefreshLinkedLines(mi, linkedLines);

            pe.MasterManager.RegisterModifingItem(mi);
            pe.MasterManager.RefreshAutoNumberStrings();

            if (lockedWidgetsCount > 0)
            {
                MessageBox.Show("　　有【 " + lockedWidgetsCount.ToString() + " 】个部件处于被锁定状态，不可移动。已复位。",
                    Globals.AppName, MessageBoxButton.OK, MessageBoxImage.Warning);
            }

            return string.Empty;
        }

        #endregion
    }
}
